﻿using System;
using System.Collections.Generic;
using System.IO;
using Grundy.Common;
using Grundy.CryptographicServices;
using Grundy.Entity;
using Grundy.Key.RsaProvider;
using Grundy.Message;
using log4net;
using FluentValidation;
using System.Linq;

namespace Grundy.Client
{
    public class ClientConfiguration
    {
        static ContainerValidator _containerValidator = new ContainerValidator();
        private static WindowsApiIdentityProvider _windowsApiIdentityProvider = new WindowsApiIdentityProvider();

        static ClientConfiguration _instance = new ClientConfiguration();
        public static ClientConfiguration Instance { get { return _instance; } }

        public CryptographicServicesProvider ServerCryptographicServicesProvider { get; private set; }
        public CryptographicServicesProvider EntitlementServerCryptographicServicesProvider { get; private set; }

        public string LicenseServerAddress { get; set; }
        public int LicenseServerPort { get; set; }
        public int MaximumMessageSize { get; set; }
        public IdentifierCollection ApiIdentity { get {return _windowsApiIdentityProvider.GetIdentifiers();} }
        private static ILog _logger = LogManager.GetLogger(typeof(ClientConfiguration));
        public string LicenseDirectoryPath { get; set; }
        public string LicenseFileExtension { get; set; }

        public IEnumerable<CustomerLicenseEntitlement> NodeLockedEntitlements { get; private set; }

        protected ClientConfiguration()
        {
            ServerCryptographicServicesProvider = new RsaProvider(Server_RsaProvider_Public.Key);
            EntitlementServerCryptographicServicesProvider = new RsaProvider(EntitlementServer_RsaProvider_Public.Key);
            
            LicenseServerAddress = "LOCALHOST";
            LicenseServerPort = 2225;
            MaximumMessageSize = 32768;
            LicenseDirectoryPath = ".";
            LicenseFileExtension = "glf";

            NodeLockedEntitlements = GetNodeLockedFeatures(LicenseDirectoryPath, LicenseFileExtension, EntitlementServerCryptographicServicesProvider);
        }

        private List<CustomerLicenseEntitlement> GetNodeLockedFeatures(string licenseDirectoryPath, string licenseFileExtension, CryptographicServicesProvider ecsp)
        {
            var nodeLockedFeatures = new List<CustomerLicenseEntitlement>();

            var nodeFingerprintIdentityProvider = new NodeFingerprintIdentityProvider();
            nodeFingerprintIdentityProvider.IgnoreMacAddresses = true;
            var nodeIdentity = nodeFingerprintIdentityProvider.GetIdentifiers();
                
            var path = licenseDirectoryPath;
            
            var licenseFiles = Directory.EnumerateFiles(path, "*.{0}".FormatWith(licenseFileExtension));
            var licenseManager = new LicenseManager(ecsp);
            foreach (var licenseFile in licenseFiles)
            {
                try
                {
                    var license = File.ReadAllText(licenseFile);
                    var c = license.Deserialize<Container>();
                    _containerValidator.ValidateAndThrow(c);
                    var ce = licenseManager.CreateCustomerEntitlementFromLicense(c);
                    // Check only for node locked licenses here
                    var featuresForThisNode = ce.LicenseEntitlements
                                                  .Where(i => i.License is NodeLockedLicense)
                                                  .Where(i =>
                                                            {
                                                                var comparer = new NodeIdentityComparer(i.Node.Identifiers);
                                                                return comparer.Matches(nodeIdentity);
                                                            })
                                                  .Select(i => GetCustomerProductLicenseEntitlement(ce, i, new byte[0]));
                    nodeLockedFeatures.AddRange(featuresForThisNode);
                }
                catch (Exception ex)
                {
                    _logger.ErrorFormat("License file {0} is not valid. Message: {1} \r\nDetails: {2}", licenseFile, ex.Message, ex.ToString());
                }
            }

            return nodeLockedFeatures;
        }

        private CustomerLicenseEntitlement GetCustomerProductLicenseEntitlement(CustomerEntitlement c, LicenseEntitlement i, byte[] decryptedCustomerKey)
        {
            return new CustomerLicenseEntitlement(c.Customer.Id, c.Customer.Name, i, decryptedCustomerKey);
        }
    }
}